﻿using System;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;

namespace Tszy.Unlimited.Data.AdoNet.Sql.Components
{
    /// <summary>
    /// 查询处理器。
    /// </summary>
    /// <typeparam name="TSource">数据实体类型。</typeparam>
    public interface IExecuteQuery<TSource>
    {
        /// <summary>
        /// 执行 SQL 查询脚本并返回数据集合。
        /// </summary>
        /// <returns>数据集合。</returns>
        QueryEnumerableResult<TSource> ToEnumerable();

        /// <summary>
        /// 执行 SQL 查询脚本并返回数据集合。
        /// </summary>
        /// <returns>数据集合。</returns>
        Task<QueryEnumerableResult<TSource>> ToEnumerableAsync();

        /// <summary>
        /// 执行 SQL 查询脚本并返回第一条数据。
        /// </summary>
        /// <returns>数据。</returns>
        TSource FirstOrDefault();

        /// <summary>
        /// 执行 SQL 查询脚本并返回第一条数据。
        /// </summary>
        /// <returns>数据。</returns>
        Task<TSource> FirstOrDefaultAsync();

        /// <summary>
        /// 执行 SQL 查询脚本并返回第一条数据。
        /// </summary>
        /// <param name="predicate">查询条件。</param>
        /// <returns>数据。</returns>
        TSource FirstOrDefault(Expression<Func<TSource, bool>> predicate);

        /// <summary>
        /// 执行 SQL 查询脚本并返回第一条数据。
        /// </summary>
        /// <param name="predicate">查询条件。</param>
        /// <returns>数据。</returns>
        Task<TSource> FirstOrDefaultAsync(Expression<Func<TSource, bool>> predicate);

        /// <summary>
        /// 执行 SQL。
        /// </summary>
        /// <typeparam name="T">返回数据类型。</typeparam>
        /// <returns>数据。</returns>
        T Execute<T>();

        /// <summary>
        /// 执行 SQL。
        /// </summary>
        /// <typeparam name="T">返回数据类型。</typeparam>
        /// <returns>数据。</returns>
        Task<T> ExecuteAsync<T>();
    }

    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="TSource"></typeparam>
    /// <typeparam name="TResult"></typeparam>
    public abstract class ExecuteQueryBase<TSource, TResult> : IExecuteQuery<TResult>
      where TSource : new()
    {
        /// <summary>
        /// 查询对象。
        /// </summary>
        protected readonly IQuery<TSource> _query;

        /// <summary>
        /// 初始化。
        /// </summary>
        /// <param name="query">查询对象。</param>
        protected ExecuteQueryBase(IQuery<TSource> query)
        {
            _query = query;
        }

        /// <summary>
        ///
        /// </summary>
        /// <returns></returns>
        public abstract QueryEnumerableResult<TResult> ToEnumerable();

        /// <summary>
        ///
        /// </summary>
        /// <returns></returns>
        public abstract Task<QueryEnumerableResult<TResult>> ToEnumerableAsync();

        /// <summary>
        ///
        /// </summary>
        /// <returns></returns>
        public TResult FirstOrDefault()
        {
            _query.Context.Take = 1;
            var result = ToEnumerable();

            if (result.Status)
                return result.List.FirstOrDefault();

            return default;
        }

        /// <summary>
        ///
        /// </summary>
        /// <returns></returns>
        public async Task<TResult> FirstOrDefaultAsync()
        {
            _query.Context.Take = 1;
            var result = await ToEnumerableAsync();

            if (result.Status)
                return result.List.FirstOrDefault();

            return default;
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public abstract TResult FirstOrDefault(Expression<Func<TResult, bool>> predicate);

        /// <summary>
        ///
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public abstract Task<TResult> FirstOrDefaultAsync(Expression<Func<TResult, bool>> predicate);

        /// <summary>
        ///
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public abstract T Execute<T>();

        /// <summary>
        ///
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public abstract Task<T> ExecuteAsync<T>();
    }
}